﻿/******************************************************************************
 * Name         : Socket.hpp
 * Author       : 671643387
 * Date         : 2015年9月6日
 * Description  : 套接字类
 *****************************************************************************/

#ifndef NET_SOCKET_HPP_
#define NET_SOCKET_HPP_

#include <dev/net/SocketApi.hpp>

namespace dev
{
    namespace net
    {
        class TcpConnection;
        class TcpAcceptor;

        /**
         * @brief 套接字
         */
        class Socket
        {
        private:
            friend class TcpConnection;
            friend class TcpAcceptor;

        public:
            Socket(int domain, int type, int protocol = 0);
            Socket(sock_t sockfd);
            ~Socket();

        public:
            /**
             * @brief 获取本地套接字
             * @return sock_t
             */
            sock_t getSocket() const { return sock_; }

            /**
             * @brief 判断套接字是否有效
             * @return bool
             */
            bool isValid(void) const { return sock_ != INVALID_SOCKET; }

            /**
             * @brief 设置套接字阻塞状态
             * @param on    是否阻塞
             * @return bool
             */
            bool setNonBlocking(bool on = true);

            /**
             * @brief 设置套接字阻塞是否重用地址
             * @param on    是否重用地址
             * @return bool
             */
            bool setReuseAddr(bool on = false);

            /**
             * @brief 设置套接字linger状态
             * @param on    
             * @return bool
             */
            bool setLinger(bool on = false);

        public:

            /**
             * @brief 重置内部原始本地套接字
             * @param sock
             */
            void reset(sock_t sock);

        public:
            /**
             * @brief 获取用户数据
             * @return void*
             */
            void* getUserDataPtr() { return userData_.ptr; }

            /**
             * @brief 获取用户数据
             * @return int
             */
            int getUserDataInt() { return userData_.ival; }

            /**
             * @brief 获取用户数据
             * @return long
             */
            long getUserDataLong() { return userData_.lval; }

            /**
             * @brief 设置用户数据
             * @param void*
             */
            void setUserDataPtr(void* pV) { userData_.ptr = pV; }

            /**
             * @brief 设置用户数据
             * @param int
             */
            void setUserDataInt(int x) { userData_.ival = x; }

            /**
             * @brief 设置用户数据
             * @param long
             */
            void setUserDataLong(long x) { userData_.lval = x; }

        public:
            /**
             * @brief 接收数据
             * @param buff      数据缓存
             * @param length    数据缓存长度
             * @param flags     标志
             * @return 成功返回接收的数据长度，如果套接字非阻塞且数据
             *         已接收完返回SOCKET_ERROR_WOULDBLOCK，错误返回SOCKET_ERROR
             */
            int receive(char* buff, size_t length, int flags = 0);

            /**
             * @brief 发送数据
             * @param buff      数据缓存
             * @param length    数据缓存长度
             * @param flags     标志
             * @return 成功发送接收的数据长度，如果套接字非阻塞且数据
             *         发送缓存已满返回SOCKET_ERROR_WOULDBLOCK，错误返回SOCKET_ERROR
             */
            int send(const char* buff, size_t length, int flags = 0);

        public:
            /**
             * @brief 关闭套接字
             */
            void close(void);
            
        private:
            sock_t sock_;   // 本地套接字

            union
            {
                void* ptr;
                int ival;
                long lval;
            } userData_;    // 用户数据
        };
    }
}

#endif /* NET_SOCKET_HPP_ */
